package be.kul.osgi.ds.myagent.message;

import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import be.kul.osgi.ds.messageservice.MessageObject;
import be.kul.osgi.ds.myagent.MyAgent;

public class ContractNetInitiator implements BasicBehaviour{

	private static int TIMEOUT = 1000;
	public FSM fsm;
	public MessageObject mes;
	public MyAgent agent;
	public ArrayList<MessageObject> proposals;
	private String ID;
	private String task;
	private String capabilities;
	public ArrayList<BasicBehaviour> todo;
	
	public ContractNetInitiator(MyAgent agent, String task, String capabilities){
		fsm = new FSM(agent, this.getID());
		this.agent = agent;
		this.task = task;
		this.capabilities = capabilities;
		this.ID = agent.getMesID();
		proposals = new ArrayList<MessageObject>();
		fsm = new FSM(agent, this.ID);
		this.todo = new ArrayList<BasicBehaviour>();
	}
	
	public String getID(){
		return this.ID;
	}

	@Override
	public void HandleMessage(MessageObject mo) {
		if ((mo.getPerformative() == MessageObject.PROPOSE)){
				//System.out.println("fsm will handle proposal");
				fsm.handle(mo);	
		}
		
		if ((mo.getPerformative() == MessageObject.REFUSE)){
			fsm.handle(mo);	
		}
		
		if ((mo.getPerformative() == MessageObject.FAILURE)){
			fsm.handle(mo);	
		}
		
		if ((mo.getPerformative() == MessageObject.INFORM)){
			fsm.handle(mo);	
		}
	}
	
	@Override
	public boolean isInterested(MessageObject mo) {
		if (this.ID.equals(mo.getConversationId())){
			if ((mo.getPerformative() == MessageObject.REFUSE) && (fsm.current == 0)){
				return true;
			}
			
			if ((mo.getPerformative() == MessageObject.PROPOSE) && (fsm.current == 0)){
				return true;
			}
			
			if ((mo.getPerformative() == MessageObject.FAILURE) && (fsm.current == 1)){
				return true;
			}
			
			if ((mo.getPerformative() == MessageObject.INFORM) && (fsm.current == 1)){
				return true;
			}
			
		} else {
			//System.out.println("ID's dont match : " + this.ID + " and " + mo.getConversationId());
		}
		return false;
	}
	
	public void doCFP(){		
		//send message
		mes = new MessageObject(MessageObject.CFP);
		mes.setReplyByDate(new Date(System.currentTimeMillis()+TIMEOUT));
		mes.setReceiver("multi");
		mes.setSender(agent.name);
		mes.setConversationId(this.ID);
		String cont =  "<Content>"+ task + capabilities + "</Content>";
		mes.setContent(cont);
		String message = agent.getMessageService().serialize(mes);
		
		System.out.println(message);
		
		//start FSM
		agent.getComm().sendmulticast(message);
		
		Date timeToRun = new Date(System.currentTimeMillis()+TIMEOUT);
		Timer timer = new Timer();

		timer.schedule(new TimerTask() {
		        public void run() {
		           System.out.println("@ContractInit - TimerTest - changestate");
		           fsm.changeState(1);
		           //sort
		           
		           
		           
		           //get best proposal
		           
		           
		           if (!proposals.isEmpty()){
		        	   
		        	   MessageObject best = proposals.get(0);
		        	   int bestval = Integer.parseInt(best.getContent());
		        	   int size = proposals.size();
		        	   for (int i = 1; i < size; i++){
		        		   int newval =  Integer.parseInt(proposals.get(i).getContent());
		        		   if (newval <= bestval){
		        			   best = proposals.get(i);
		        			   bestval = newval;
		        		   } 
		        	   }
		        	   
			           	mes = new MessageObject(MessageObject.ACCEPT_PROPOSAL);
			   			//mes.setReplyByDate(new Date(System.currentTimeMillis()+TIMEOUT));
			   			mes.setReceiver(best.getSender());
			   			mes.setSender(agent.name);
			   			mes.setConversationId(best.getConversationId());
				   		String message = agent.getMessageService().serialize(mes);
				   		agent.getComm().sendmulticast(message);
				   		
				   		proposals.remove(best);
				   		for(int i = 1; i < proposals.size(); i++){
				   			MessageObject reject = proposals.get(i);
				           	mes = new MessageObject(MessageObject.REJECT_PROPOSAL);
				   			//mes.setReplyByDate(new Date(System.currentTimeMillis()+TIMEOUT));
				   			mes.setReceiver(reject.getSender());
				   			mes.setSender(agent.name);
				   			mes.setConversationId(best.getConversationId());
				   			message = agent.getMessageService().serialize(mes);
				   			agent.getComm().sendmulticast(message);
				   		}
		           }
			        
		   		
		           //send messages
		        }
		}, timeToRun);
	}
	
	public class FSM {
		   // 2. States array
		   private State[] states  = { new CFP(), new HandleInform(), new Done() } ;
		   
		   // 3. Current state
		   private int     current = 0;
		   
		   private MyAgent pagent;
		   private String ID;
		   
		   
		   // 4. Delegation and pass the this pointer
		   public void handle(MessageObject m)  { states[current].handle(  this , m); }
		   
		   public void changeState( int index ) { current = index; }
		   
		   
		   public FSM(MyAgent a,String ID){
			   pagent = a;
			   this.ID = ID;
		   }
		   
		   public MyAgent getAgent(){
			   return pagent;
		   }
		   
		   public int getState(){
			   return current;
		   }
		   
		}

		// 5. The State base class
		abstract class State {
		   // 6. Default behavior
		   public void handle(  FSM fsm, MessageObject m ){
			   
		   }
		 }

		class CFP extends State {
		   
			//handle what comes in after sending the CFP
			public void handle(  final FSM fsm, MessageObject m) { 
				 if (m.getPerformative()== MessageObject.PROPOSE){
					   //add proposal to list
					 System.out.println("proposal added");
					   proposals.add(m);
				   } //refusals not handled
		    }
		
		}

		// 7. Only override some messages
		class HandleInform extends State {
		   // 8. "call back to" the wrapper class
		   @Override
			public void handle( FSM fsm, MessageObject m ) { 
				 
			}   
		}
		
		class Done extends State {
			   // 8. "call back to" the wrapper class
			   @Override
			public void handle( FSM fsm, MessageObject m ) { 
				   System.out.println( "@ContractInit, State Done!" );
				 }   
			}

		@Override
		public void start() {
			// TODO Auto-generated method stub
			
		}

}
